package com.yqtsoft.utils.excel.core;

import com.yqtsoft.utils.excel.annotation.ExcelAttribute;
import com.yqtsoft.utils.excel.annotation.ExcelElement;
import com.yqtsoft.utils.excel.config.ElementTypePath;
import org.apache.poi.hssf.usermodel.DVConstraint;
import org.apache.poi.hssf.usermodel.HSSFDataValidation;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.util.CellRangeAddressList;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 常用方法封装
 *
 * @author: CrazyShaQiuShi
 * @email: 3105334046@qq.com
 * @date: 2018-11-25 12:51
 * @version: 1.0
 */
public abstract class AbstractExcelUtilss<T> extends AbstractExcelUtil<T> {

    /**
     * 获取所有字段
     *
     * @param clazz
     * @param listField
     * @return List<Field> 返回类型
     * @throws
     */
    protected List<Field> getAllField(Class<?> clazz, List<Field> listField) {
        if (listField == null) {
            listField = new ArrayList<>();
        }
        // 获取所有属性
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            Type fieldType = field.getType();

            if (field.isAnnotationPresent(ExcelAttribute.class)) {
                listField.add(field);
                // 类名,属性名
            } else if (field.isAnnotationPresent(ExcelElement.class)) {
                /**
                 * TODO 类型判断
                 */
                switch (ElementTypePath.getElementTypePath(fieldType.getTypeName())) {
                    case SET:
                    case LIST:
                        Type genericFieldType = field.getGenericType();
                        getAllField(getClass(genericFieldType, 0), listField);
                        break;
                    case MAP:
                        listField.add(field);
                        break;
                    default:
                        getAllField(field.getClass(), null);
                        break;
                }
            }
        }

        return listField;
    }

    /**
     * 得到泛型类对象
     *
     * @param type
     * @param i
     * @return
     */
    protected static Class getClass(Type type, int i) {
        if (type instanceof ParameterizedType) {
            // 处理泛型类型
            return getGenericClass((ParameterizedType) type, i);
        } else if (type instanceof TypeVariable) {
            // 处理泛型擦拭对象
            return (Class) getClass(((TypeVariable) type).getBounds()[0], 0);
        } else {
            // class本身也是type，强制转型
            return (Class) type;
        }
    }

    private static Class getGenericClass(ParameterizedType parameterizedType, int i) {
        Object genericClass = parameterizedType.getActualTypeArguments()[i];
        if (genericClass instanceof ParameterizedType) {
            // 处理多级泛型
            return (Class) ((ParameterizedType) genericClass).getRawType();
        } else if (genericClass instanceof GenericArrayType) {
            // 处理数组泛型
            return (Class) ((GenericArrayType) genericClass).getGenericComponentType();
        } else if (genericClass instanceof TypeVariable) {
            // 处理泛型擦拭对象
            return (Class) getClass(((TypeVariable) genericClass).getBounds()[0], 0);
        } else {
            return (Class) genericClass;
        }
    }

    /**
     * 将EXCEL中A,B,C,D,E列映射成0,1,2,3
     *
     * @param col
     */
    protected static int getExcelCol(String col) {
        col = col.toUpperCase();
        // 从-1开始计算,字母重1开始运算。这种总数下来算数正好相同。
        int count = -1;
        char[] cs = col.toCharArray();
        for (int i = 0; i < cs.length; i++) {
            count += (cs[i] - 64) * Math.pow(26, cs.length - 1 - i);
        }
        return count;
    }

    /**
     * 设置单元格上提示
     *
     * @param sheet         要设置的sheet.
     * @param promptTitle   标题
     * @param promptContent 内容
     * @param firstRow      开始行
     * @param endRow        结束行
     * @param firstCol      开始列
     * @param endCol        结束列
     * @return 设置好的sheet.
     */
    protected static HSSFSheet setHSSFPrompt(HSSFSheet sheet, String promptTitle, String promptContent, int firstRow,
                                             int endRow, int firstCol, int endCol) {
        // 构造constraint对象
        DVConstraint constraint = DVConstraint.createCustomFormulaConstraint("DD1");
        // 四个参数分别是：起始行、终止行、起始列、终止列
        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
        // 数据有效性对象
        HSSFDataValidation data_validation_view = new HSSFDataValidation(regions, constraint);
        data_validation_view.createPromptBox(promptTitle, promptContent);
        sheet.addValidationData(data_validation_view);
        return sheet;
    }

    /**
     * 设置某些列的值只能输入预制的数据,显示下拉框.
     *
     * @param sheet    要设置的sheet.
     * @param textlist 下拉框显示的内容
     * @param firstRow 开始行
     * @param endRow   结束行
     * @param firstCol 开始列
     * @param endCol   结束列
     * @return 设置好的sheet.
     */
    protected static HSSFSheet setHSSFValidation(HSSFSheet sheet, String[] textlist, int firstRow, int endRow,
                                                 int firstCol, int endCol) {
        // 加载下拉列表内容
        DVConstraint constraint = DVConstraint.createExplicitListConstraint(textlist);
        // 设置数据有效性加载在哪个单元格上,四个参数分别是：起始行、终止行、起始列、终止列
        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
        // 数据有效性对象
        HSSFDataValidation data_validation_list = new HSSFDataValidation(regions, constraint);
        sheet.addValidationData(data_validation_list);
        return sheet;
    }


}
